#include <intr/irq.h>
#include <asm/asm.h>
#include <macros.h>
#include <intr/idt.h>
#include <printk.h>
#include <keyboard/key.h>

#if 0
#define SAVE_ALL_REGS                      \
    "cld \n\t"                             \
    "pushq   %rax \n\t"                    \
    "pushq	%rbx \n\t"                     \
    "pushq	%rcx \n\t"                     \
    "pushq	%rdx \n\t"                     \
    "pushq	%rsi \n\t"                     \
    "pushq	%rdi \n\t"                     \
    "pushq	%rbp \n\t"                     \
    "pushq	%r8 \n\t"                      \
    "pushq	%r9 \n\t"                      \
    "pushq	%r10 \n\t"                     \
    "pushq	%r11 \n\t"                     \
    "pushq	%r12 \n\t"                     \
    "pushq	%r13 \n\t"                     \
    "pushq	%r14 \n\t"                     \
    "pushq	%r15 \n\t"                     \
    "xorq    %rax, %rax \n\t"              \
    "movq	%ds,	%rax \n\t"             \
    "pushq	%rax \n\t"                     \
    "xorq    %rax, %rax \n\t"              \
    "movq	%es,	%rax \n\t"             \
    "pushq	%rax \n\t"                     \
    "movq $0x10, %rdi \n\t"                \
    "movq %rdi, %es \n\t"                  \
    "movq %rdi, %ds \n\t"

/*

*/

#define IRQ_FUNC(nr) nr##_interrupt(void)
#define IRQ_NAME(nr) IRQ_FUNC(IRQ_##nr)

/*

*/

#define Build_IRQ(nr)                                                           \
    void IRQ_NAME(nr);                                                          \
    __asm__(SYMBOL_TO_STR(IRQ_) #nr "_interrupt: \n\t"                          \
                                     "xchgw %bx, %bx \n\t"                      \
                                     "pushq	$0x00 \n\t"                         \
                                     "pushq %rax \n\t"                          \
                                     "leaq IRQn_func(%rip), %rax \n\t"          \
                                     "xchgq %rax, (%rsp) \n"                    \
                                     SAVE_ALL_REGS                              \
                                     "movq	%rsp,	%rdi \n\t"                  \
                                     "leaq	restore_from_intr(%rip), %rax \n\t" \
                                     "pushq	%rax \n\t"                          \
                                     "movq	$" #nr ", %rsi \n\t"                \
                                     "jmp	IRQn_func \n\t");

Build_IRQ(0xe0)
Build_IRQ(0xe1)
Build_IRQ(0xe2)
Build_IRQ(0xe3)
Build_IRQ(0xe4)
Build_IRQ(0xe5)
Build_IRQ(0xe6)
Build_IRQ(0xe7)
Build_IRQ(0xe8)
Build_IRQ(0xe9)
Build_IRQ(0xea)
Build_IRQ(0xeb)
Build_IRQ(0xec)
Build_IRQ(0xed)
Build_IRQ(0xee)
Build_IRQ(0xef)






static void IRQn_func(intr_arg_t *arg, u64_t seqno) {
    u8_t x;
	printk("do_IRQ:%#016lx\t", seqno);
	io_in8(0x60, x);
	printk("key code:%#016lx\t",x);
	send_EOI(seqno-IRQ_MAP_MASTER_OFF);
	printk("<RIP:%#016lx\tRSP:%#016lx>\n",arg->rip,arg->rsp);
}
#endif

static void (*g_irq_funcs[16])(void) = {
    NULL,
    keyboadr_isr,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL
};

static inline void io_wait(void)
{
    io_out8(0x80, 0);
}
static inline void setup_irqs(void)
{
}

static inline void pic_disable_bits(u8_t master, u8_t slave)
{
    io_out8(PIC_DATA_MASTER, master);
    io_out8(PIC_DATA_SLAVE, slave);
}

static inline void pic_enable_all(void)
{
    io_out8(PIC_DATA_MASTER, 0x00);
    io_out8(PIC_DATA_SLAVE, 0x00);
}

void send_EOI(u8_t irq)
{
    if (irq >= 8)
    {
        io_out8(PIC_COMMAND_SLAVE, PIC_EOI);
    }

    io_out8(PIC_COMMAND_MASTER, PIC_EOI);
}
void init_irqs(u32_t master_off, u32_t slave_off)
{
    // u8_t r1, r2;

    
    // set_intr_gate(0xe0+1, 1, timer_isr); //timer
    set_intr_gate(0xe0+1, 1, g_irq_funcs[1]); //keyboard
    

    // 保存寄存器状态
    // io_in8(PIC_DATA_MASTER, r1);
    // io_in8(PIC_DATA_SLAVE, r2);

    io_out8(PIC_MASTER, ICW1_ICW4 | ICW1_INIT); // ICW1 MASTER
    io_wait();
    io_out8(PIC_SLAVE, ICW1_ICW4 | ICW1_INIT); // ICW1 SLAVE
    io_wait();

    io_out8(PIC_DATA_MASTER, master_off); // ICW2 MASTER
    io_wait();
    io_out8(PIC_DATA_SLAVE, slave_off); // ICW2 SLAVE
    io_wait();

    io_out8(PIC_DATA_MASTER, 0x04); // ICW3 MASTER
    io_wait();
    io_out8(PIC_DATA_SLAVE, 0x02); // ICW3 SLAVE
    io_wait();

    io_out8(PIC_DATA_MASTER, ICW4_8086); // ICW4 MASTER
    io_wait();
    io_out8(PIC_DATA_SLAVE, ICW4_8086); // ICW4 SLAVE
    io_wait();

    // 恢复寄存器状态
    // io_out8(PIC_DATA_MASTER, r1);
    // io_out8(PIC_DATA_SLAVE, r2);

    pic_disable_bits(0xfd, 0xff);
    printk("IRQs init completed\n");

}